package com.example.dingdong.websocketSchedule;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import com.example.dingdong.websocketService.WebSocketService;



/**
 * WebSocket 定时任务
 */
@Component
@EnableScheduling
public class WebSocketSchedulingTask {

	private static final Logger log = LoggerFactory.getLogger(WebSocketSchedulingTask.class);

	@Autowired
	private WebSocketService webSocketService;

	/**
	 * webSocket 定时任务
	 * 
	 * @throws Exception void
	 */
	@Async
	@Scheduled(fixedDelay = 1000)
	public void webSocketSchedulingTask() {
		reducedKeepAliveTime();
	}

	/**
	 * 减少 WebSocket 存活时间
	 * 
	 * @throws IOException
	 */
	@Async
	public void reducedKeepAliveTime() {
		// 1、获取 WebSocket 存活时间 Map
		ConcurrentHashMap<String, Long> tokenRelateKeepAliveTime = webSocketService.getIpAddressRelateKeepAliveTime();
		Iterator<Map.Entry<String, Long>> iterator = tokenRelateKeepAliveTime.entrySet().iterator();
		// 2、遍历存活时间集合
		while (iterator.hasNext()) {
			Map.Entry<String, Long> entry = iterator.next();
			String token = entry.getKey();
			Long keepAliveTime = tokenRelateKeepAliveTime.computeIfPresent(token, (key, value) -> --value);

			// 3、存活时间小于等于零则删除连接同时清除数据
			if (keepAliveTime <= 0) {
				log.info("WebSocket heartTimeOut 存活时间内未获取到心跳，关闭连接，token: " + token);
				cleanWebSocketConnect(token);
			}
		}
	}

	/**
	 * 清理 WebSocket 连接
	 * 
	 * @throws IOException
	 */
	@Async
	public void cleanWebSocketConnect(String token) {
		if (token == null) {
			return;
		}

		// 1、关闭 WebSocketSession 连接
		WebSocketSession webSocketSession = webSocketService.getSessions().get(token);
		try {
			webSocketSession.close();
		} catch (Exception e) {
			log.warn("WebSocket heartTimeOut 定时清理 webSocket 连接失败，token : " + token + "  错误原因:", e);
		}

		// 2、删除会话和过期时间
		webSocketService.getSessions().remove(token);
		webSocketService.getIpAddressRelateKeepAliveTime().remove(token);
	}

	/**
	 * 注入定时器
	 */
	@Bean
	public TaskScheduler taskScheduler() {
		ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
		taskScheduler.setPoolSize(10);
		taskScheduler.initialize();
		return taskScheduler;
	}

}
